home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld Examples / Scrolling - Multiple Layers / Multiple Layers Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-25  |  21.7 KB  |  785 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // Multiple Layers Demo.c
  3. //
  4. // By Vern Jensen. Just a slightly modified version of the Scrolling Demo.
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11.  
  12. #include "SWApplication.h"
  13. #include "Multiple Layers Demo.h"
  14.  
  15.  
  16. #define    kFullScreenWindow            true        // Try me full screen!
  17. #define kDoubleSize                    true        // Doubles size of extraBackFrameP
  18. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  19. #define    kInterlacedMode                false        // Turns Interlaced mode on/off
  20. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  21. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  22.  
  23.  
  24. #define    kSpriteMoveDelta            20            // Try 5, 10, 20, or 40
  25. #define kDiamondSpace                8            // How far apart the diamonds are spaced
  26.                                                 // (try 1!)
  27.  
  28. #define kSpriteMoveDistance            80            // How far the sprite can move from
  29.                                                 // the center of the screen, in pixels.
  30.                                                 // Try making this value higher!
  31.  
  32.     // Number of ticks to wait before changing tile image; 0 = change every frame
  33. #define kDiamondFrameRate            8            // How often diamond tiles change frames
  34. #define kWallFrameRate                120            // How often wall changes frames
  35.  
  36. #define kBWPictResIDOffset            100
  37. #define kTileWidth                    40
  38. #define kTileHeight                    40
  39. #define kTileMapRows                100
  40. #define kTileMapCols                150
  41.  
  42. #define kStartRow                    5            // Starting position of sprite
  43. #define kStartCol                    5            // in tile col and row
  44.  
  45.  
  46. #define    kLeftArrowKey                0x7B
  47. #define    kRightArrowKey                0x7C
  48. #define    kDownArrowKey                0x7D
  49. #define    kUpArrowKey                    0x7E
  50.  
  51. #define    kLeftKeyPad                    0x56
  52. #define    kRightKeyPad                0x58
  53. #define    kDownKeyPad                    0x54
  54. #define    kUpKeyPad                    0x5B
  55.  
  56. #define kEscKey                        0x35
  57.  
  58.  
  59. #define kNoKey                        0
  60. #define kLeftKey                    1
  61. #define kUpKey                        2
  62. #define kRightKey                    3
  63. #define kDownKey                    4
  64.  
  65.  
  66. enum tileIDs
  67. {
  68.     kWallTile,
  69.     kLastWallTile,
  70.     kGrassTile,
  71.     kBlackTile,
  72.     kFirstDiamondTile,
  73.     kMiddleDiamondTile,
  74.     kLastDiamondTile,
  75.     kWireTile,
  76.     
  77.     kMaxNumTiles
  78. };
  79.  
  80.  
  81.  
  82. /***********/
  83. /* Globals */
  84. /***********/
  85.  
  86. SpriteWorldPtr        gSpriteWorldP;
  87. SpriteLayerPtr        gSpriteLayerP;
  88. TileMapStructPtr    gTileMapStructP, gSecondTileMapStructP;
  89. TileMapPtr            gTileMap;
  90. SpritePtr            gSimpleSpriteP, gDiamondMeterSpriteP;
  91. DrawProcPtr            gSpriteDrawProc, gScreenDrawProc;
  92. DoubleDrawProcPtr    gDoubleRectDrawProc;
  93. WindowPtr            gWindowP;
  94. Rect                gScreenMidRect;
  95.  
  96. long                gNumDiamondsInMap = 0;    // Number of diamonds in the TileMap
  97. long                gNumDiamonds = 0;        // Number of diamonds sprite has collected
  98.  
  99. struct moveKeys        // Keeps track of which keys are up and which are down
  100. {
  101.     Boolean    up;
  102.     Boolean    right;
  103.     Boolean    down;
  104.     Boolean    left;
  105. } gKeys;
  106.  
  107.  
  108. ///--------------------------------------------------------------------------------------
  109. // Main
  110. ///--------------------------------------------------------------------------------------
  111.  
  112. void    main( void )
  113. {
  114.     Initialize(kNumberOfMoreMastersCalls);
  115.  
  116.     if (SWHasSystem7())
  117.     {
  118.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  119.         SetCursor(*GetCursor(watchCursor));
  120.         
  121.         CreateSpriteWorld();
  122.         SetUpTiling();
  123.         CreateBallSprite();
  124.         CreateDiamondMeterSprite();
  125.         
  126.         SetCursor(&qd.arrow);
  127.         HideCursor();
  128.         
  129.         SetUpAnimation();
  130.         RunAnimation();
  131.         ShutDown();
  132.         
  133.         RestoreEventMask();    // Call this after AllowKeyUpEvents
  134.     }
  135.     else
  136.     {
  137.         CantRunOnThisMachine();
  138.     }
  139. }
  140.  
  141.  
  142. ///--------------------------------------------------------------------------------------
  143. // CreateSpriteWorld
  144. ///--------------------------------------------------------------------------------------
  145.  
  146. void    CreateSpriteWorld( void )
  147. {
  148.     Rect        offscreenRect, worldRect, windRect;
  149.     RgnHandle    mBarUpdateRgn;
  150.     OSErr        err;
  151.     
  152.     gWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  153.     
  154.     if (gWindowP != NULL)
  155.     {
  156.         if (kFullScreenWindow == true)
  157.         {
  158.             SizeWindow(gWindowP, qd.screenBits.bounds.right, 
  159.                     qd.screenBits.bounds.bottom, false);
  160.             MoveWindow(gWindowP, 0, 0, false);
  161.         }
  162.         else
  163.         {
  164.                 // Center window in screen
  165.             windRect = gWindowP->portRect;
  166.             CenterRect(&windRect, &qd.screenBits.bounds);
  167.             
  168.                 // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  169.             windRect.left = windRect.left>>2<<2;
  170.             
  171.             MoveWindow(gWindowP, windRect.left, windRect.top, false);
  172.         }
  173.         
  174.         ShowWindow(gWindowP);
  175.         SetPort(gWindowP);
  176.         mBarUpdateRgn = SWHideMenuBar(gWindowP); // Must be done *after* showing window!
  177.         EraseRgn(mBarUpdateRgn);
  178.         
  179.         if (kInterlacedMode)
  180.             PaintRect(&gWindowP->portRect);    // Blacken window for Interlaced mode
  181.     }
  182.     else
  183.         CantFindResource();
  184.     
  185.     
  186.     err = SWEnterSpriteWorld();
  187.     FatalError(err);
  188.     
  189.     
  190.     worldRect = gWindowP->portRect;
  191.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  192.     
  193.     
  194.         // Set size of offscreen area
  195.     offscreenRect = worldRect;
  196.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  197.     
  198.  
  199.         // Make offscreen area evenly divisible by tile width & height
  200.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  201.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  202.     
  203.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  204.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  205.     
  206.         // Create the scrolling sprite world
  207.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  208.             &worldRect, &offscreenRect, 0);
  209.     FatalError(err);
  210.     
  211.             // Create the sprite layer
  212.     err = SWCreateSpriteLayer(&gSpriteLayerP);
  213.     FatalError(err);
  214.     
  215.         // Add it to the world
  216.     SWAddSpriteLayer(gSpriteWorldP, gSpriteLayerP);
  217.     
  218.     
  219.         // Determine what DrawProcs to use
  220.     if (gSpriteWorldP->pixelDepth == 8)        // 256 colors
  221.     {
  222.         if (kInterlacedMode)
  223.         {
  224.             gSpriteDrawProc = BP8BitInterlacedMaskDrawProc;
  225.             gScreenDrawProc = BP8BitInterlacedRectDrawProc;
  226.             gDoubleRectDrawProc = BP8BitInterlacedDoubleRectDrawProc;
  227.             SWSetPartialMaskDrawProc(gSpriteWorldP, BP8BitInterlacedPartialMaskDrawProc);
  228.         }
  229.         else
  230.         {
  231.             gSpriteDrawProc = BlitPixie8BitMaskDrawProc;
  232.             gScreenDrawProc = SWStdWorldDrawProc;
  233.             gDoubleRectDrawProc = BlitPixie8BitDoubleRectDrawProc;
  234.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixie8BitPartialMaskDrawProc);
  235.         }
  236.     }
  237.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )    // Not 256 colors
  238.     {
  239.             // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  240.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  241.         {
  242.             gSpriteDrawProc = BPAllBitInterlacedMaskDrawProc;
  243.             gScreenDrawProc = BPAllBitInterlacedRectDrawProc;
  244.             SWSetPartialMaskDrawProc(gSpriteWorldP, BPAllBitInterlacedPartialMaskDrawProc);
  245.             if (gSpriteWorldP->pixelDepth == 16)
  246.                 gDoubleRectDrawProc = BP16BitInterlacedDoubleRectDrawProc;
  247.         }
  248.         else
  249.         {
  250.             gSpriteDrawProc = BlitPixieAllBitMaskDrawProc;
  251.             gScreenDrawProc = BlitPixieAllBitRectDrawProc;
  252.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  253.             if (gSpriteWorldP->pixelDepth == 16)
  254.                 gDoubleRectDrawProc = BlitPixie16BitDoubleRectDrawProc;
  255.         }
  256.     }
  257.     else
  258.     {
  259.         gSpriteDrawProc = SWStdSpriteDrawProc;
  260.         gScreenDrawProc = SWStdWorldDrawProc;
  261.         gDoubleRectDrawProc = NULL;
  262.     }
  263. }
  264.     
  265.     
  266. ///--------------------------------------------------------------------------------------
  267. // SetUpTiling
  268. ///--------------------------------------------------------------------------------------
  269.  
  270. void    SetUpTiling( void )    
  271. {
  272.     TileMapPtr        tileMap;
  273.     short            row, col;
  274.     OSErr            err;
  275.     
  276.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  277.     FatalError(err);
  278.     
  279.     err = SWCreateTileMap(&gTileMapStructP, kTileMapRows, kTileMapCols);
  280.     FatalError(err);
  281.     
  282.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  283.     gTileMap = gTileMapStructP->tileMap;
  284.  
  285.         // Load first set of tiles
  286.     err = SWLoadTilesFromPictResource(
  287.         gSpriteWorldP, 
  288.         kWallTile,                // startTileID 
  289.         kBlackTile,                // endTileID
  290.         200,                    // pictResID
  291.         0,                        // maskResID
  292.         kNoMask,                // maskType
  293.         0,                        // horizBorderWidth
  294.         0);                        // vertBorderHeight
  295.     FatalError(err);
  296.     
  297.         // Load self-masked diamond tiles
  298.     err = SWLoadTilesFromPictResource(
  299.         gSpriteWorldP, 
  300.         kFirstDiamondTile,        // startTileID 
  301.         kLastDiamondTile,        // endTileID
  302.         201,                    // pictResID
  303.         201,                    // maskResID
  304.         kFatMask,                // maskType
  305.         0,                        // horizBorderWidth
  306.         0);                        // vertBorderHeight
  307.     FatalError(err);
  308.     
  309.         // Load the wire tile
  310.     err = SWLoadTileFromCicnResource(
  311.         gSpriteWorldP, 
  312.         kWireTile,            // tileID
  313.         131,                 // CICN resource ID
  314.         kFatMask);            // maskType
  315.     FatalError(err);
  316.  
  317.     
  318.         // Set up tileMap
  319.     for (row = 0; row < kTileMapRows; row++)
  320.     {
  321.         for (col = 0; col < kTileMapCols; col++)
  322.         {
  323.             if (row == 0 || col == 0 || row == kTileMapRows-1 || col == kTileMapCols-1)
  324.                 gTileMap[row][col] = kWallTile;
  325.             else if (row > kTileMapRows / 2)
  326.                 gTileMap[row][col] = -1;
  327.             else if ((row/kDiamondSpace)*kDiamondSpace == row && 
  328.                      (col/kDiamondSpace)*kDiamondSpace == col)
  329.             {
  330.                 gTileMap[row][col] = kFirstDiamondTile;
  331.                 gNumDiamondsInMap++;
  332.             }
  333.             else
  334.                 gTileMap[row][col] = kGrassTile;
  335.         }
  336.     }
  337.     
  338.  
  339.     
  340.         // Create the second tileMap
  341.     err = SWCreateTileMap(&gSecondTileMapStructP, kTileMapRows, kTileMapCols);
  342.     FatalError(err);
  343.     
  344.     SWInstallTileMap(gSpriteWorldP, gSecondTileMapStructP, 1);
  345.     tileMap = gSecondTileMapStructP->tileMap;
  346.     
  347.         // Set up tileMap
  348.     for (row = 0; row < kTileMapRows; row++)
  349.     {
  350.         for (col = 0; col < kTileMapCols; col++)
  351.         {
  352.             if (col > kTileMapCols / 2)
  353.                 tileMap[row][col] = kWireTile;
  354.             else
  355.                 tileMap[row][col] = -1;
  356.         }
  357.     }
  358. }
  359.  
  360.  
  361. ///--------------------------------------------------------------------------------------
  362. // CreateBallSprite
  363. ///--------------------------------------------------------------------------------------
  364.  
  365. void    CreateBallSprite( void )
  366. {
  367.     OSErr    err;
  368.     
  369.         // Create the ball sprite
  370.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSimpleSpriteP, NULL, 
  371.             129, 1, kFatMask);    
  372.     FatalError(err);
  373.     
  374.         // Set up the ball sprite
  375.     SWAddSprite(gSpriteLayerP, gSimpleSpriteP);
  376.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  377.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  378.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  379.     SWSetSpriteDrawProc(gSimpleSpriteP, gSpriteDrawProc);
  380. }
  381.  
  382.  
  383. ///--------------------------------------------------------------------------------------
  384. // CreateDiamondMeterSprite
  385. ///--------------------------------------------------------------------------------------
  386.  
  387. void    CreateDiamondMeterSprite( void )
  388. {
  389.     OSErr        err;
  390.     
  391.         // Create the diamond meter sprite
  392.     err = SWCreateSpriteFromPictResource(gSpriteWorldP,
  393.                 &gDiamondMeterSpriteP, 
  394.                 NULL,            // pointer to memory for sprite
  395.                 202,             // picture resource id
  396.                 202,            // mask resource id
  397.                 1,                 // max frames
  398.                 kPixelMask);    // mask type
  399.     FatalError(err);
  400.     
  401.     SWAddSprite(gSpriteLayerP, gDiamondMeterSpriteP);
  402.     SWSetSpriteDrawProc(gDiamondMeterSpriteP, gSpriteDrawProc);
  403. }
  404.  
  405.  
  406. ///--------------------------------------------------------------------------------------
  407. // SetUpAnimation
  408. ///--------------------------------------------------------------------------------------
  409.  
  410. void    SetUpAnimation( void )
  411. {
  412.     Rect        moveBoundsRect, extraBackRect;
  413.     short        row, col;
  414.     PicHandle    backPictH;
  415.     OSErr        err;
  416.     
  417.     SWLockSpriteWorld(gSpriteWorldP);
  418.     
  419.         // Set up data used by the SmoothScrollingWorldMoveProc
  420.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  421.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  422.     
  423.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  424.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  425.     SWSetCleanUpSpriteWorld(gSpriteWorldP);
  426.     
  427.         // movement boundary = size of tileMap
  428.     SetRect(&moveBoundsRect, 0,0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  429.     
  430.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  431.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  432.     
  433.     SWSetSpriteLayerUnderTileLayer(gSpriteLayerP, 1);
  434.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  435.     
  436.         // Move visScrollRect to starting sprite position
  437.     SWMoveVisScrollRect(gSpriteWorldP, 
  438.         gSpriteWorldP->followSpriteP->destFrameRect.left - gSpriteWorldP->backRect.right/2,
  439.         gSpriteWorldP->followSpriteP->destFrameRect.top - gSpriteWorldP->backRect.bottom/2);
  440.     
  441.         // Set starting position of diamond meter sprite
  442.     DiamondMeterSpriteMoveProc(gDiamondMeterSpriteP);
  443.  
  444.     SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, gScreenDrawProc);
  445.     SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, gScreenDrawProc);
  446.     SWSetDoubleRectDrawProc(gSpriteWorldP, gDoubleRectDrawProc);    
  447.     SWSetTileMaskDrawProc(gSpriteWorldP, gSpriteDrawProc);
  448.     
  449.         // Make sure CopyBits, if used, doesn't try to colorize things
  450.     SWSetPortToWindow(gSpriteWorldP);
  451.     ForeColor(blackColor);
  452.     BackColor(whiteColor);
  453.     
  454.     backPictH = GetPicture(128);    // Color pict
  455.  
  456.     if (backPictH == nil)
  457.         FatalError(-1);
  458.     
  459.     extraBackRect = (**(backPictH)).picFrame;
  460.     
  461.     if (kDoubleSize)
  462.     {
  463.         extraBackRect.right *= 2;
  464.         extraBackRect.bottom *= 2;
  465.     }
  466.     
  467.     err = SWCreateExtraBackFrame(gSpriteWorldP, &extraBackRect);
  468.     FatalError(err);
  469.     SWLockFrame(gSpriteWorldP->extraBackFrameP);
  470.     SWSetPortToExtraBackFrame(gSpriteWorldP);
  471.     DrawPicture(backPictH, &extraBackRect);
  472.     ReleaseResource((Handle)backPictH);
  473.     
  474.         // Erase the tile directly beneath the Sprite's starting position
  475.     row = gSimpleSpriteP->destFrameRect.top / kTileHeight;
  476.     col = gSimpleSpriteP->destFrameRect.left / kTileWidth;
  477.     gTileMap[row][col] = -1;
  478.  
  479.     SWDrawTilesInBackground(gSpriteWorldP);
  480.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  481. }
  482.  
  483.  
  484. ///--------------------------------------------------------------------------------------
  485. //  RunAnimation
  486. ///--------------------------------------------------------------------------------------
  487.  
  488. void    RunAnimation( void )
  489. {
  490.     unsigned long        frames;
  491.         
  492.     frames = 0;
  493.     StartTimer();
  494.  
  495.  
  496.     while (!Button())
  497.     {
  498.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  499.         
  500.             // We call this in case the Control Strip or something changes our window's visRgn
  501.         KeepMenuBarHidden(gWindowP);
  502.  
  503.             // Move diamond meter sprite to new visScrollRect location
  504.         DiamondMeterSpriteMoveProc(gDiamondMeterSpriteP);
  505.     
  506.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  507.         
  508.         if (gSpriteWorldP->frameHasOccurred)
  509.             frames++;
  510.     }
  511.     
  512.     
  513.     ShowResults(frames);
  514.     SWShowMenuBar(gWindowP);
  515. }
  516.  
  517.  
  518. ///--------------------------------------------------------------------------------------
  519. //  ShutDown (clean up and dispose of the SpriteWorld)
  520. ///--------------------------------------------------------------------------------------
  521.  
  522. void    ShutDown( void )
  523. {
  524.     SWDisposeSpriteWorld(&gSpriteWorldP);
  525.     SWDisposeTileMap(&gTileMapStructP);            // SWDisposeSpriteWorld will not 
  526.     SWDisposeTileMap(&gSecondTileMapStructP);    // dispose our TileMaps for us.
  527.     SWExitSpriteWorld();
  528.     
  529.     FlushEvents(everyEvent, 0);
  530.     ShowCursor();
  531. }
  532.  
  533.  
  534. ///--------------------------------------------------------------------------------------
  535. //  TileChangeProc
  536. ///--------------------------------------------------------------------------------------
  537.  
  538. SW_FUNC void TileChangeProc(
  539.     SpriteWorldPtr spriteWorldP)
  540. {
  541.     short            curImage;
  542.     static short    wallDelay = 0, diamondDelay = 0;
  543.     static short    oldTicks = 0;
  544.     short            ticksPassed, ticks;
  545.     
  546.         // Initialize oldTicks the first time this function is called
  547.     if (oldTicks == 0)
  548.         oldTicks = TickCount();
  549.     
  550.     ticks = TickCount();
  551.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  552.     oldTicks = ticks;
  553.     
  554.         // kWallTile
  555.     wallDelay += ticksPassed;
  556.     if (wallDelay >= kWallFrameRate)
  557.     {
  558.         curImage = spriteWorldP->curTileImage[kWallTile];
  559.         if (curImage < kLastWallTile)
  560.             curImage++;
  561.         else
  562.             curImage = kWallTile;
  563.         
  564.         SWChangeTileImage(spriteWorldP, kWallTile, curImage);
  565.         wallDelay = 0;
  566.     }
  567.     
  568.     
  569.         // kDiamondTile
  570.     diamondDelay += ticksPassed;
  571.     if (diamondDelay >= kDiamondFrameRate)
  572.     {
  573.         curImage = spriteWorldP->curTileImage[kFirstDiamondTile];
  574.         if (curImage < kLastDiamondTile)
  575.             curImage++;
  576.         else
  577.             curImage = kFirstDiamondTile;
  578.         
  579.         SWChangeTileImage(spriteWorldP, kFirstDiamondTile, curImage);
  580.         diamondDelay = 0;
  581.     }
  582. }
  583.  
  584.  
  585. ///--------------------------------------------------------------------------------------
  586. //  KeySpriteMoveProc
  587. ///--------------------------------------------------------------------------------------
  588.  
  589. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  590. {
  591.     short        row, col;
  592.     short        rowDelta, colDelta;
  593.     short        tile;
  594.     
  595.     UpdateKeys();    // Put the latest key values in the keys structure
  596.     
  597.     
  598.     row = srcSpriteP->destFrameRect.top / kTileHeight;
  599.     col = srcSpriteP->destFrameRect.left / kTileWidth;
  600.  
  601.     if (row * kTileHeight == srcSpriteP->destFrameRect.top &&
  602.         col * kTileWidth == srcSpriteP->destFrameRect.left)
  603.     {        
  604.         rowDelta = 0;
  605.         colDelta = 0;
  606.         
  607.         if (gKeys.left)
  608.             colDelta = -1;
  609.         else if (gKeys.right)
  610.             colDelta = 1;
  611.         else if (gKeys.up)
  612.             rowDelta = -1;
  613.         else if (gKeys.down)
  614.             rowDelta = 1;
  615.         
  616.         tile = gTileMap[row + rowDelta][col + colDelta];
  617.         
  618.         if (tile != kWallTile)
  619.         {
  620.             srcSpriteP->vertMoveDelta = rowDelta * kSpriteMoveDelta;
  621.             srcSpriteP->horizMoveDelta = colDelta * kSpriteMoveDelta;
  622.         }
  623.         else
  624.         {
  625.             srcSpriteP->vertMoveDelta = 0;
  626.             srcSpriteP->horizMoveDelta = 0;
  627.         }
  628.     }
  629.     
  630.     if (srcSpriteP->vertMoveDelta || srcSpriteP->horizMoveDelta)
  631.     {
  632.         SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  633.         
  634.             // Determine if the sprite is completely within the grid after moving
  635.         row = srcSpriteP->destFrameRect.top / kTileHeight;
  636.         col = srcSpriteP->destFrameRect.left / kTileWidth;
  637.  
  638.         if (row * kTileHeight == srcSpriteP->destFrameRect.top &&
  639.             col * kTileWidth == srcSpriteP->destFrameRect.left)
  640.         {
  641.                 // We're aligned with the grid, so do things normally
  642.             tile = gTileMap[row][col];
  643.         
  644.                 // Leave black trail behind sprite
  645.             if (tile == kGrassTile || tile == kFirstDiamondTile)
  646.                 SWDrawTile(gSpriteWorldP, 0, row, col, -1);    // kBlackTile
  647.  
  648.             if (tile == kFirstDiamondTile)
  649.             {
  650.                 gNumDiamonds++;            // Increase number of diamonds sprite has collected
  651.                 UpdateDiamondMeter();    // Update meter
  652.             }
  653.         }
  654.         else    
  655.         {
  656.                 // We're not aligned with the grid, so erase the piece of grass
  657.                 // tile the Sprite has just moved over, if it just ran over some grass.
  658.             if (srcSpriteP->horizMoveDelta > 0)
  659.                 col++;
  660.             else if (srcSpriteP->vertMoveDelta > 0)
  661.                 row++;
  662.             
  663.             if (gTileMap[row][col] == kGrassTile)
  664.             {
  665.                 gTileMap[row][col] = -1;
  666.             
  667.                     // I'm breaking a rule here by calling an undocumented function.
  668.                     // It is not recommended that you do this in your own code, but is
  669.                     // necessary in this case for the effect I want to achieve.
  670.                 (*gSpriteWorldP->tileRectDrawProc)(gSpriteWorldP, &srcSpriteP->destFrameRect, false);
  671.                 SWWrapRectToWorkArea(gSpriteWorldP, &srcSpriteP->destFrameRect);
  672.                 gTileMap[row][col] = kGrassTile;
  673.             }
  674.         }
  675.     }
  676. }
  677.  
  678.  
  679. ///--------------------------------------------------------------------------------------
  680. //  DiamondMeterSpriteMoveProc - not installed as a MoveProc, but called directly
  681. ///--------------------------------------------------------------------------------------
  682.  
  683. SW_FUNC void DiamondMeterSpriteMoveProc(SpritePtr srcSpriteP)
  684. {
  685.         // Move sprite to top-left corner of current visScrollRect location
  686.     SWMoveSprite(srcSpriteP, 
  687.         gSpriteWorldP->visScrollRect.left + 10, 
  688.         gSpriteWorldP->visScrollRect.top + 10);
  689. }
  690.  
  691.  
  692. ///--------------------------------------------------------------------------------------
  693. //  UpdateDiamondMeter - change the meter Sprite's image and mask
  694. ///--------------------------------------------------------------------------------------
  695.  
  696. SW_FUNC void UpdateDiamondMeter( void )
  697. {
  698.     double    percent;
  699.     Rect    meterRect;
  700.     
  701.     percent = (double)gNumDiamonds / gNumDiamondsInMap;
  702.     
  703.         // 108 = length of meter; 17 = offset from start of meter
  704.     SetRect(&meterRect, 17, 2, (108 * percent) + 17, 14);
  705.     
  706.     
  707.         // Set port to our sprite's framePort GWorld
  708.     SetGWorld(gDiamondMeterSpriteP->curFrameP->framePort, nil);
  709.     
  710.     ForeColor(magentaColor);
  711.     PaintRect(&meterRect);
  712.     
  713.         // IMPORTANT: Set the color back when done! (In case CopyBits is used later)
  714.     ForeColor(blackColor);
  715.     
  716.     
  717.         // Set port to our sprite's pixel mask GWorld
  718.     SetGWorld(gDiamondMeterSpriteP->curFrameP->maskPort, nil);
  719.     
  720.         // Mask image is inverted when in 8-bit or less
  721.     if (gSpriteWorldP->pixelDepth <= 8)
  722.         ForeColor(whiteColor);
  723.     else
  724.         ForeColor(blackColor);
  725.     
  726.     PaintRect(&meterRect);
  727.     ForeColor(blackColor);
  728.     
  729.     
  730.         // Set sprite to be redrawn, since we've changed its image
  731.     gDiamondMeterSpriteP->needsToBeDrawn = true;
  732. }
  733.  
  734.  
  735. ///--------------------------------------------------------------------------------------
  736. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  737. ///--------------------------------------------------------------------------------------
  738.  
  739. SW_FUNC void SmoothScrollingWorldMoveProc(
  740.     SpriteWorldPtr spriteWorldP,
  741.     SpritePtr followSpriteP)
  742. {    
  743.     short    screenMidRectTop, screenMidRectLeft;
  744.     
  745.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  746.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  747.     
  748.     
  749.     spriteWorldP->horizScrollDelta = (kSpriteMoveDelta * 
  750.         (followSpriteP->destFrameRect.left - screenMidRectLeft) ) / kSpriteMoveDistance;
  751.     
  752.     spriteWorldP->vertScrollDelta = (kSpriteMoveDelta * 
  753.         (followSpriteP->destFrameRect.top - screenMidRectTop) ) / kSpriteMoveDistance;
  754.     
  755.     if (kInterlacedMode)
  756.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  757. }
  758.  
  759.  
  760. ///--------------------------------------------------------------------------------------
  761. //  UpdateKeys (Put the latest key values in the keys structure)
  762. ///--------------------------------------------------------------------------------------
  763.  
  764. void    UpdateKeys( void )
  765. {
  766.     EventRecord        event;
  767.     short            theKey;
  768.     Boolean            isDown;
  769.     
  770.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  771.     {
  772.         theKey = (event.message & keyCodeMask) >> 8;
  773.         isDown = (event.what != keyUp);
  774.         
  775.         if ( (theKey == kLeftArrowKey) || (theKey == kLeftKeyPad) )
  776.             gKeys.left = isDown;
  777.         else if ( (theKey == kRightArrowKey) || (theKey == kRightKeyPad) )
  778.             gKeys.right = isDown;
  779.         else if ( (theKey == kDownArrowKey) || (theKey == kDownKeyPad) )
  780.             gKeys.down = isDown;
  781.         else if ( (theKey == kUpArrowKey) || (theKey == kUpKeyPad) )
  782.             gKeys.up = isDown;
  783.     }
  784. }
  785.